/**
 * Actor Throughput Benchmark
 * 
 * This benchmark measures how many messages an actor can process per second.
 * It creates a specified number of actors and sends messages to them as fast as possible.
 */
import { Kameo } from '../src/index';
import { loadConfig } from './config';
import { formatNumber, timeExecution, runConcurrently } from './utils';

/**
 * Message counter actor interface
 */
interface CounterMessage {
  action: 'increment' | 'get';
  amount?: number;
}

async function main() {
  console.log('🚀 Starting Actor Throughput Benchmark');
  
  // Load benchmark configuration
  const config = loadConfig({
    // Override default config if needed
    duration: 5,
    actorCount: 10
  });
  
  console.log(`\nBenchmark Configuration:`);
  console.log(`- Duration: ${config.duration} seconds`);
  console.log(`- Actor Count: ${config.actorCount}`);
  
  // Initialize Kameo
  const kameo = new Kameo();
  await kameo.init();
  
  console.log('\nInitializing actors...');
  
  // Create actors
  const actors = Array.from({ length: config.actorCount }, (_, i) => {
    return kameo.spawn<CounterMessage, number>('counter', { initialCount: 0 });
  });
  
  console.log(`Created ${config.actorCount} counter actors`);
  
  // Warm-up phase
  console.log('\nWarm-up phase...');
  await Promise.all(actors.map(actor => actor.tell({ action: 'increment', amount: 1 })));
  
  // Benchmark phase
  console.log('\nStarting benchmark...');
  const startTime = Date.now();
  const endTime = startTime + (config.duration * 1000);
  
  let totalMessages = 0;
  
  // Run benchmark until the duration is reached
  while (Date.now() < endTime) {
    // Use Promise.all to send messages to all actors in parallel
    await Promise.all(actors.map(actor => {
      return actor.tell({ action: 'increment', amount: 1 })
        .then(() => { totalMessages++; });
    }));
  }
  
  const actualDuration = (Date.now() - startTime) / 1000;
  const messagesPerSecond = totalMessages / actualDuration;
  
  // Print results
  console.log('\n📊 Benchmark Results:');
  console.log(`Total messages processed: ${formatNumber(totalMessages)}`);
  console.log(`Actual duration: ${formatNumber(actualDuration, 'seconds')}`);
  console.log(`Throughput: ${formatNumber(messagesPerSecond, 'messages/sec')}`);
  console.log(`Average latency: ${formatNumber(1000 / messagesPerSecond, 'ms')}`);
  
  // Get final counts from actors to verify
  console.log('\nVerifying actor state...');
  const [finalCounts, verifyTime] = await timeExecution(async () => {
    return Promise.all(actors.map(actor => actor.ask({ action: 'get' })));
  });
  
  const totalCount = finalCounts.reduce((sum, count) => sum + count, 0);
  
  console.log(`Verification time: ${formatNumber(verifyTime, 'ms')}`);
  console.log(`Total counter value across all actors: ${formatNumber(totalCount)}`);
  
  // Cleanup
  console.log('\nBenchmark complete!');
}

// Run the benchmark
main().catch(error => {
  console.error('Benchmark failed:', error);
  process.exit(1);
}); 